package com.laf.common.utils.image;

import com.laf.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;

/**
 * 用于生成灰度图
 */
@Slf4j
public class GrayscaleUtils {

    // 获取线程池
    private static ThreadPoolTaskExecutor executor = SpringUtils.getBean("threadPoolTaskExecutor");

    // 获取上传文件ben对象
    private static FileStorageService fileStorageService = SpringUtils.getBean(FileStorageService.class);

    // 灰度图文件存储位置
    private static String objectName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd/")) + "grayscale/";

    private static final int CONCURRENT_LIMIT = 10; // 控制并发数为10

    /**
     * 利用线程池来实现灰度图转换和上传图片
     *
     * @param originUrls 原始图片的 URL 列表
     * @return 上传成功的灰度图 URL 列表
     * @throws Exception
     */
    public static List<String> generateGrayscale(List<String> originUrls)   {
        List<String> resultUrls = new ArrayList<>();
        Semaphore semaphore = new Semaphore(CONCURRENT_LIMIT); // 控制并发数为
        List<CompletableFuture<String>> futures = new ArrayList<>();

        for (String originUrl : originUrls) {
            // 创建异步任务
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                try {
                    semaphore.acquire(); // 获取许可
                    // 下载图片并且转换为灰度图
                    BufferedImage originalImage = downloadImage(new URL(originUrl));
                    BufferedImage grayImage = convertToGrayscale(originalImage);

                    // 上传图片
                    String resultUrl = uploadImage(grayImage);
                    return resultUrl;

                } catch (IOException  e) {
                    log.error("GrayscaleUtils.generateGrayscale 转换灰度图失败: " + e.getMessage());
                    return null;
                } catch (InterruptedException e) {
                    log.error("GrayscaleUtils.generateGrayscale 线程池中断: " + e.getMessage());
                    return null;
                }finally {
                    semaphore.release(); // 释放许可
                }
            }, executor);

            futures.add(future);
        }

        // 等待所有异步任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        // 收集所有任务的结果
        for (CompletableFuture<String> future : futures) {
            String resultUrl = future.join();
            if (resultUrl != null) {
                resultUrls.add(resultUrl);
            }
        }

        return resultUrls;
    }

    /**
     * 利用 ImageIO 下载图片
     * @param url
     * @return
     * @throws IOException
     */
    private static BufferedImage downloadImage(URL url) throws IOException {
        log.info("Downloading image from URL: " + url);
        return ImageIO.read(url);
    }

    /**
     * 将 BufferedImage 转换为灰度图
     * @param originalImage
     * @return
     * @throws IOException
     */
    private static BufferedImage convertToGrayscale(BufferedImage originalImage) throws IOException {
        log.info("Converting image to grayscale");
        BufferedImage grayImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g2d = grayImage.createGraphics();
        g2d.drawImage(originalImage, 0, 0, null);
        g2d.dispose();
        return grayImage;
    }

    /**
     * 上传灰度图
     * @param grayImage
     * @return
     * @throws IOException
     */
    private static String uploadImage(BufferedImage grayImage) throws IOException {
        log.info("Uploading grayscale image");
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(grayImage, "jpg", outputStream);
        byte[] bytes = outputStream.toByteArray();

        FileInfo fileInfo = fileStorageService.of(bytes)
                .setPath(objectName)
                .upload();

        return fileInfo.getUrl();
    }
}
